﻿/// ****************************************************************************
/// Author:	        Robin Zhu
/// Create Date:	2013-4-30
/// Purpose: 		类构建函数代理类文件
/// ****************************************************************************
/// Modify By		Date			Remark
/// Robin           2013-5-14       防止类没有可用构造函数而引发的Exception
/// ****************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;

namespace RB.DataAccess
{
    /// <summary>
    /// 类构造函数代理接口
    /// </summary>
    public interface IClassConstructor
    {
        object CreateInstance(params object[] parameters);
    }

    /// <summary>
    /// 类构造函数代理接口工厂类
    /// </summary>
    public class ClassConstructorFactory
    {
        /// <summary>
        /// 判断一个类是否有默认构造函数(参数数量为0）
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static bool HasDefaultConstructor(Type t)
        {
            return (t.GetConstructor(Type.EmptyTypes) != null);
        }

        /// <summary>
        /// 创建某个类型的构造函数代理
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static IClassConstructor Create<T>()
        {
            IClassConstructor result = null;

            Type t = typeof(T);

            if (HasDefaultConstructor(t))
            {
                result = new ClassConstructor<T>();
            }
            else
            {
                var constructorInfos = t.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                if (constructorInfos.Length > 0)
                {
                    var constructorInfo = constructorInfos[0];

                    var parameters = constructorInfo.GetParameters();
                    var paramCount = parameters.Length;

                    if (paramCount < 10)
                    {
                        Type ccType = null;
                        switch (paramCount)
                        {
                            case 1:
                                ccType = typeof(ClassConstructor<,>).MakeGenericType(t, parameters[0].ParameterType);
                                break;
                            case 2:
                                ccType = typeof(ClassConstructor<,,>).MakeGenericType(t, parameters[0].ParameterType, parameters[1].ParameterType);
                                break;
                            case 3:
                                ccType = typeof(ClassConstructor<,,,>).MakeGenericType(t, parameters[0].ParameterType, parameters[1].ParameterType, parameters[2].ParameterType);
                                break;
                            case 4:
                                ccType = typeof(ClassConstructor<,,,,>).MakeGenericType(t, parameters[0].ParameterType, parameters[1].ParameterType, parameters[2].ParameterType, parameters[3].ParameterType);
                                break;
                            case 5:
                                ccType = typeof(ClassConstructor<,,,,,>).MakeGenericType(t, parameters[0].ParameterType, parameters[1].ParameterType, parameters[2].ParameterType, parameters[3].ParameterType, parameters[4].ParameterType);
                                break;
                            case 6:
                                ccType = typeof(ClassConstructor<,,,,,,>).MakeGenericType(t, parameters[0].ParameterType, parameters[1].ParameterType, parameters[2].ParameterType, parameters[3].ParameterType, parameters[4].ParameterType, parameters[5].ParameterType);
                                break;
                            case 7:
                                ccType = typeof(ClassConstructor<,,,,,,,>).MakeGenericType(t, parameters[0].ParameterType, parameters[1].ParameterType, parameters[2].ParameterType, parameters[3].ParameterType, parameters[4].ParameterType, parameters[5].ParameterType, parameters[6].ParameterType);
                                break;
                            case 8:
                                ccType = typeof(ClassConstructor<,,,,,,,,>).MakeGenericType(t, parameters[0].ParameterType, parameters[1].ParameterType, parameters[2].ParameterType, parameters[3].ParameterType, parameters[4].ParameterType, parameters[5].ParameterType, parameters[6].ParameterType, parameters[7].ParameterType);
                                break;
                            case 9:
                                ccType = typeof(ClassConstructor<,,,,,,,,,>).MakeGenericType(t, parameters[0].ParameterType, parameters[1].ParameterType, parameters[2].ParameterType, parameters[3].ParameterType, parameters[4].ParameterType, parameters[5].ParameterType, parameters[6].ParameterType, parameters[7].ParameterType, parameters[8].ParameterType);
                                break;
                        }
                        result = (IClassConstructor)Activator.CreateInstance(ccType, constructorInfo, parameters);
                    }
                    else
                    {
                        result = new ClassConstructor(constructorInfo);
                    }
                }
            }
            return result;
        }
    }

    /// <summary>
    /// 非delegate方式的构造函数类，使用ConstructorInfo（反射）构造类的对象实例
    /// </summary>
    public class ClassConstructor : IClassConstructor
    {
        private ConstructorInfo _constructorInfo = null;

        public ClassConstructor(ConstructorInfo constructorInfo)
        {
            _constructorInfo = constructorInfo;
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructorInfo.Invoke(parameters);
        }
    }

    /// <summary>
    /// 无参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ClassConstructor<T> : IClassConstructor
    {
        private Func<T> _constructor = null;

        public ClassConstructor()
        {
            Type t = typeof(T);

            var exprNew = Expression.New(t);
            var lambda = Expression.Lambda<Func<T>>(exprNew);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor();
        }
    }

    /// <summary>
    /// 一个参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="P"></typeparam>
    public class ClassConstructor<T, P> : IClassConstructor
    {
        private Func<P, T> _constructor = null;

        public ClassConstructor(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
        {
            var parameter = Expression.Parameter(parameterInfos[0].ParameterType);
            var exprNew = Expression.New(constructorInfo, parameter);
            var lambda = Expression.Lambda<Func<P, T>>(exprNew, parameter);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor((P)parameters[0]);
        }
    }

    /// <summary>
    /// 两个参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="P1"></typeparam>
    /// <typeparam name="P2"></typeparam>
    public class ClassConstructor<T, P1, P2> : IClassConstructor
    {
        private Func<P1, P2, T> _constructor = null;

        public ClassConstructor(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
        {
            var parameters = parameterInfos.Select(p => Expression.Parameter(p.ParameterType)).ToArray();
            var exprNew = Expression.New(constructorInfo, parameters);
            var lambda = Expression.Lambda<Func<P1, P2, T>>(exprNew, parameters);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor((P1)parameters[0], (P2)parameters[1]);
        }
    }

    /// <summary>
    /// 三个参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="P1"></typeparam>
    /// <typeparam name="P2"></typeparam>
    /// <typeparam name="P3"></typeparam>
    public class ClassConstructor<T, P1, P2, P3> : IClassConstructor
    {
        private Func<P1, P2, P3, T> _constructor = null;

        public ClassConstructor(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
        {
            var parameters = parameterInfos.Select(p => Expression.Parameter(p.ParameterType)).ToArray();
            var exprNew = Expression.New(constructorInfo, parameters);
            var lambda = Expression.Lambda<Func<P1, P2, P3, T>>(exprNew, parameters);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor((P1)parameters[0], (P2)parameters[1], (P3)parameters[2]);
        }
    }

    /// <summary>
    /// 四个参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="P1"></typeparam>
    /// <typeparam name="P2"></typeparam>
    /// <typeparam name="P3"></typeparam>
    /// <typeparam name="P4"></typeparam>
    public class ClassConstructor<T, P1, P2, P3, P4> : IClassConstructor
    {
        private Func<P1, P2, P3, P4, T> _constructor = null;

        public ClassConstructor(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
        {
            var parameters = parameterInfos.Select(p => Expression.Parameter(p.ParameterType)).ToArray();
            var exprNew = Expression.New(constructorInfo, parameters);
            var lambda = Expression.Lambda<Func<P1, P2, P3, P4, T>>(exprNew, parameters);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor((P1)parameters[0], (P2)parameters[1], (P3)parameters[2], (P4)parameters[3]);
        }
    }

    /// <summary>
    /// 五个参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="P1"></typeparam>
    /// <typeparam name="P2"></typeparam>
    /// <typeparam name="P3"></typeparam>
    /// <typeparam name="P4"></typeparam>
    /// <typeparam name="P5"></typeparam>
    public class ClassConstructor<T, P1, P2, P3, P4, P5> : IClassConstructor
    {
        private Func<P1, P2, P3, P4, P5, T> _constructor = null;

        public ClassConstructor(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
        {
            var parameters = parameterInfos.Select(p => Expression.Parameter(p.ParameterType)).ToArray();
            var exprNew = Expression.New(constructorInfo, parameters);
            var lambda = Expression.Lambda<Func<P1, P2, P3, P4, P5, T>>(exprNew, parameters);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor((P1)parameters[0], (P2)parameters[1], (P3)parameters[2], (P4)parameters[3], (P5)parameters[4]);
        }
    }

    /// <summary>
    /// 六个参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="P1"></typeparam>
    /// <typeparam name="P2"></typeparam>
    /// <typeparam name="P3"></typeparam>
    /// <typeparam name="P4"></typeparam>
    /// <typeparam name="P5"></typeparam>
    /// <typeparam name="P6"></typeparam>
    public class ClassConstructor<T, P1, P2, P3, P4, P5, P6> : IClassConstructor
    {
        private Func<P1, P2, P3, P4, P5, P6, T> _constructor = null;

        public ClassConstructor(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
        {
            var parameters = parameterInfos.Select(p => Expression.Parameter(p.ParameterType)).ToArray();
            var exprNew = Expression.New(constructorInfo, parameters);
            var lambda = Expression.Lambda<Func<P1, P2, P3, P4, P5, P6, T>>(exprNew, parameters);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor((P1)parameters[0], (P2)parameters[1], (P3)parameters[2], (P4)parameters[3], (P5)parameters[4], (P6)parameters[5]);
        }
    }

    /// <summary>
    /// 七个参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="P1"></typeparam>
    /// <typeparam name="P2"></typeparam>
    /// <typeparam name="P3"></typeparam>
    /// <typeparam name="P4"></typeparam>
    /// <typeparam name="P5"></typeparam>
    /// <typeparam name="P6"></typeparam>
    /// <typeparam name="P7"></typeparam>
    public class ClassConstructor<T, P1, P2, P3, P4, P5, P6, P7> : IClassConstructor
    {
        private Func<P1, P2, P3, P4, P5, P6, P7, T> _constructor = null;

        public ClassConstructor(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
        {
            var parameters = parameterInfos.Select(p => Expression.Parameter(p.ParameterType)).ToArray();
            var exprNew = Expression.New(constructorInfo, parameters);
            var lambda = Expression.Lambda<Func<P1, P2, P3, P4, P5, P6, P7, T>>(exprNew, parameters);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor((P1)parameters[0], (P2)parameters[1], (P3)parameters[2], (P4)parameters[3], (P5)parameters[4], (P6)parameters[5], (P7)parameters[6]);
        }
    }

    /// <summary>
    /// 八个参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="P1"></typeparam>
    /// <typeparam name="P2"></typeparam>
    /// <typeparam name="P3"></typeparam>
    /// <typeparam name="P4"></typeparam>
    /// <typeparam name="P5"></typeparam>
    /// <typeparam name="P6"></typeparam>
    /// <typeparam name="P7"></typeparam>
    /// <typeparam name="P8"></typeparam>
    public class ClassConstructor<T, P1, P2, P3, P4, P5, P6, P7, P8> : IClassConstructor
    {
        private Func<P1, P2, P3, P4, P5, P6, P7, P8, T> _constructor = null;

        public ClassConstructor(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
        {
            var parameters = parameterInfos.Select(p => Expression.Parameter(p.ParameterType)).ToArray();
            var exprNew = Expression.New(constructorInfo, parameters);
            var lambda = Expression.Lambda<Func<P1, P2, P3, P4, P5, P6, P7, P8, T>>(exprNew, parameters);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor((P1)parameters[0], (P2)parameters[1], (P3)parameters[2], (P4)parameters[3], (P5)parameters[4], (P6)parameters[5], (P7)parameters[6], (P8)parameters[7]);
        }
    }

    /// <summary>
    /// 九个参数的Delegate方式的构造函数类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="P1"></typeparam>
    /// <typeparam name="P2"></typeparam>
    /// <typeparam name="P3"></typeparam>
    /// <typeparam name="P4"></typeparam>
    /// <typeparam name="P5"></typeparam>
    /// <typeparam name="P6"></typeparam>
    /// <typeparam name="P7"></typeparam>
    /// <typeparam name="P8"></typeparam>
    /// <typeparam name="P9"></typeparam>
    public class ClassConstructor<T, P1, P2, P3, P4, P5, P6, P7, P8, P9> : IClassConstructor
    {
        private Func<P1, P2, P3, P4, P5, P6, P7, P8, P9, T> _constructor = null;

        public ClassConstructor(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
        {
            var parameters = parameterInfos.Select(p => Expression.Parameter(p.ParameterType)).ToArray();
            var exprNew = Expression.New(constructorInfo, parameters);
            var lambda = Expression.Lambda<Func<P1, P2, P3, P4, P5, P6, P7, P8, P9, T>>(exprNew, parameters);
            _constructor = lambda.Compile();
        }

        public object CreateInstance(params object[] parameters)
        {
            return _constructor((P1)parameters[0], (P2)parameters[1], (P3)parameters[2], (P4)parameters[3], (P5)parameters[4], (P6)parameters[5], (P7)parameters[6], (P8)parameters[7], (P9)parameters[8]);
        }
    }
}
